//
// Created by l00391713 on 2024/3/4.
//
#include <getopt.h>

#include <string>
#include <iostream>

#include "ParallelTcpStore.hpp"
#include "client_store_process.hpp"

struct Options
{
    std::string host = "127.0.0.1";
    uint16_t port = 0;
    bool serverMode = true;
    bool waitReady = false;
    uint32_t workerCount = 0;
};

static void Usage(const std::string &name)
{
    std::cout << "Usage:" << std::endl;
    std::cout << "\t" << name << " -H <host> ['127.0.0.1'] -p <port> -m <server|client>[server] -n <workers>[1] -w -h" << std::endl;
    std::cout << "Options:" << std::endl;
    std::cout << "\t -H <host> : client mode given to connect to with node." << std::endl;
    std::cout << "\t -p <port> : tcp port for net connection." << std::endl;
    std::cout << "\t -m <server|client> : run as client or server mode." << std::endl;
    std::cout << "\t -m <workers> : total worker count." << std::endl;
    std::cout << "\t -w : wait all workers ready." << std::endl;
    std::cout << "\t -h : print this message." << std::endl;
}

static void RunWithOptions(const Options &options)
{
    c10d::TCPStoreOptions tcpStoreOptions{};
    tcpStoreOptions.isServer = options.serverMode;
    tcpStoreOptions.port = options.port;
    if (options.workerCount > 0) {
        tcpStoreOptions.numWorkers = c10::make_optional<size_t>(options.workerCount);
    }
    tcpStoreOptions.waitWorkers = options.waitReady;

    try {
        c10d::ParallelTcpStore store{ options.host, tcpStoreOptions };
        std::cout << "Tcp Store " << (options.serverMode ? "Server" : "Client") << " Side Started." << std::endl;
        LoopProcessForStore(store);
    } catch (const std::runtime_error &e) {
        std::cerr << "exception caught: " << e.what() << std::endl;
    }
}

int main(int argc, char *argv[])
{
    int opt;
    Options options;
    bool showHelp = false;
    while ((opt = getopt(argc, argv, "H:p:m:n:wh")) != -1) {
        switch (opt) {
            case 'H':
                options.host = optarg;
                break;

            case 'p':
                options.port = std::stoi(optarg);
                break;

            case 'm':
                options.serverMode = (std::string("server") == std::string(optarg));
                break;

            case 'n':
                options.workerCount = std::stoi(optarg);
                break;

            case 'w':
                options.waitReady = true;
                break;

            case 'h':
                showHelp = true;
                break;

            default:
                std::cout << "?? getopt return character code 0" << std::oct << (uint32_t)opt << " ??" << std::endl;
                break;
        }
    }

    if (showHelp) {
        Usage(argv[0]);
        return 0;
    }

    RunWithOptions(options);
    std::cout << "already finished, press any key to exit." << std::endl;
    std::string input;
    std::getline(std::cin, input);

    return 0;
}